using System;
using System.Collections.Generic;
using Firestarter.DB.Schema.Logic;
using FireStarterModeller.BO;

namespace Firestarter.DB_DomainModel.Logic
{
    public class DBTypeToDMPropertyTypeMapper : IDBTypeToDMPropertyTypeMapper
    {
        private readonly IPropertyTypeStorer _propertyTypeStorer;
        private readonly Dictionary<string, TypeDetail> _typeMappings;

        public DBTypeToDMPropertyTypeMapper(IPropertyTypeStorer propertyTypeStorer)
        {
            _propertyTypeStorer = propertyTypeStorer;
            _typeMappings = new Dictionary<string, TypeDetail>();
            SetupDefaultTypeMappings();
        }

        private void SetupDefaultTypeMappings()
        {
            AddTypeMapping(DBDataTypes.INTEGER, "System", "Int32");
            AddTypeMapping(DBDataTypes.BIT, "System", "Boolean");
            AddTypeMapping(DBDataTypes.TIMESTAMP, "System", "DateTime");
            AddTypeMapping(DBDataTypes.BINARY, "System", "Byte[]");
            AddTypeMapping(DBDataTypes.VARBINARY, "System", "Byte[]");
            AddTypeMapping(DBDataTypes.DATETIME, "System", "DateTime");
            AddTypeMapping(DBDataTypes.DECIMAL, "System", "Decimal");
            AddTypeMapping(DBDataTypes.NUMERIC, "System", "Decimal");
            AddTypeMapping(DBDataTypes.DOUBLE, "System", "Double");
            AddTypeMapping(DBDataTypes.VARCHAR, "System", "String");
            AddTypeMapping(DBDataTypes.SMALLINT, "System", "Int16");
            AddTypeMapping(DBDataTypes.BIGINT, "System", "Int64");
            AddTypeMapping(DBDataTypes.TINYINT, "System", "Byte");
            AddTypeMapping(DBDataTypes.TINYINT + "(1)", "System", "Boolean");
            AddTypeMapping(DBDataTypes.TINYINT + "(-1)", "System", "Boolean");
            AddTypeMapping(DBDataTypes.SINGLE, "System", "Single");
            AddTypeMapping(DBDataTypes.TEXT, "System", "String");
            AddTypeMapping(DBDataTypes.CHAR, "System", "String");
            AddTypeMapping(DBDataTypes.LONGVARBINARY, "System", "Byte[]");
            AddTypeMapping(DBDataTypes.MEDIUMTEXT, "System", "String");
            AddTypeMapping(DBDataTypes.LONGTEXT, "System", "String");
            AddTypeMapping(DBDataTypes.TIME, "System", "TimeSpan");
            AddTypeMapping(DBDataTypes.UNIQUEIDENTIFIER, "System", "Guid");
        }

        private void AddTypeMapping(string universalDataTypeName, string assemblyName, string typeName)
        {
            _typeMappings.Add(universalDataTypeName, new TypeDetail(assemblyName, typeName));
        }

        public DMPropertyType GetDMPropertyType(string universalDataTypeName, int? dataLength)
        {
            TypeDetail typeDetail = null;
            if (dataLength != null)
            {
                string newDataTypeName = universalDataTypeName + "(" + dataLength + ")";
                _typeMappings.TryGetValue(newDataTypeName, out typeDetail);
            }
            if(typeDetail == null && string.IsNullOrEmpty(universalDataTypeName))
            {
                typeDetail = new TypeDetail("System", "String");
            }

            if (typeDetail == null) _typeMappings.TryGetValue(universalDataTypeName, out typeDetail);

            
            return typeDetail == null? null: _propertyTypeStorer.GetDMPropertyType(typeDetail.AssemblyName, typeDetail.TypeName);
        }

        internal class TypeDetail
        {
            public string AssemblyName { get; set; }
            public string TypeName { get; set; }

            public TypeDetail(string assemblyName, string typeName)
            {
                AssemblyName = assemblyName;
                TypeName = typeName;
            }
        }
    }
}